#include <stdio.h>     // 标准 C 输入输出
#include <sys/types.h> // 包含基本类型
#include <sys/ipc.h>   // 包含 IPC 定义和标志
#include <sys/shm.h>   // 包含共享内存定义和函数
#include <unistd.h>    // 包含 POSIX 函数，如 sleep, getpid
#include <errno.h>     // 包含错误码定义

// 定义用于生成 key 值的路径名和项目 ID
#define PATHNAME "/etc/passwd"
#define PROJ_ID 0x6666
#define SIZE 4096

int main()
{
    // 1. 生成 key 值
    key_t key = ftok(PATHNAME, PROJ_ID);
    if (key < 0)
    {
        perror("ftok");
        return 1;
    }

    // 2. 创建共享内存段，使用 IPC_CREAT | IPC_EXCL 确保是新建
    int shm_id = shmget(key, SIZE, IPC_CREAT | IPC_EXCL | 0666);
    if (shm_id < 0)
    {
        // 如果 shmget 失败且错误是 EEXIST (文件已存在)，说明共享内存已存在
        if (errno == EEXIST)
        {
            printf("共享内存已存在，尝试获取其ID...\n");
            // 尝试获取已存在的共享内存段
            shm_id = shmget(key, SIZE, 0666); // 不使用 IPC_CREAT | IPC_EXCL
            if (shm_id < 0)
            {
                perror("shmget 获取已存在共享内存失败");
                return 3;
            }
            printf("已获取到已存在的共享内存，shm_id: %d\n", shm_id);
        }
        else
        {
            perror("shmget 创建共享内存失败");
            return 2;
        }
    }
    else
    {
        // 成功创建了新的共享内存
        printf("成功创建新的共享内存！\n");
        printf("key: %x\n", key);
        printf("shm_id: %d\n", shm_id);
    }

    // 3. 演示共享内存存在一段时间
    printf("共享内存创建或获取成功，等待 2 秒...\n");
    sleep(2);

    // 4. 标记共享内存段为待删除
    // 调用 shmctl，使用 shm_id，命令为 IPC_RMID，buf 设置为 NULL
    printf("标记共享内存 (shm_id: %d) 为待删除...\n", shm_id);
    if (shmctl(shm_id, IPC_RMID, NULL) < 0)
    {
        perror("shmctl IPC_RMID"); // 如果标记删除失败，打印错误
        return 4;
    }
    printf("共享内存已标记为待删除。\n");

    // 5. 等待一段时间，观察 ipcs -m 的状态
    printf("等待 2 秒，以便观察 ipcs -m 状态...\n");
    sleep(2);

    // 6. 程序即将退出，此时本进程与共享内存的连接会自动分离
    // 由于之前标记了 IPC_RMID 且本进程是唯一附着的（如果代码这样运行）
    // 退出时隐式分离会导致物理内存被真正释放
    printf("程序退出。\n");

    return 0; // 程序正常结束
}